import datetime
import os
from collections import Counter

from django.conf import settings
from django.db.models import Q, F
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import mixins, status
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, GenericViewSet

# from apps.survey_system.file.models import FileHistory
from apps.survey_system.mini_program.filters import SurveyFilter, SurveyAccountFilter, SurveyAnswerFilter, ModuleFilter
from apps.survey_system.mini_program.serializers import SurveySerializer, SurveyAccountSerializer, SwiperSerializer, \
    ModuleListSerializer, ModuleRetrieveSerializer, FinishedSurveyAccountSerializer
from apps.survey_system.question.models import Swiper, Module
from apps.survey_system.survey.models import Survey, SurveyAccount, SurveyQuestionCategory, SurveyQuestion, \
    SurveyQuestionOption, SurveyAnswer
from utils.common import Pagination


class UploadViewSet(GenericViewSet):
    permission_classes = [IsAuthenticated]

    @action(methods=['post'], detail=False, url_path='upload')
    def upload_file(self, request, pk=None):
        """ 上传文件 """
        user = request.user
        file = request.data.get('file', None)   # 上传的文件
        dir_name = request.data.get('dir_name', '')     # 需要保存在哪里
        upload_key = request.data.get('upload_key', '')     # 表单的key
        if not all([file, dir_name, upload_key]):
            return Response({'message': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)
        file_name = file.name
        file_type = file_name.split('.')[-1]
        file_type = file_type.lower()
        dir_path = f"{settings.MEDIA_ROOT}/survey_system/{dir_name}"
        if not os.path.exists(dir_path):  # 没有该目录就创建
            os.makedirs(dir_path)
        # 给文件重新命名，避免重复
        now_str = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        new_file_name = f"{now_str}-{user.realname}.{file_type}"
        file_path = os.path.join(dir_path, new_file_name)
        # 写入文件
        with open(file_path, 'ab') as fp:
            # 如果上传的文件非常大，就通过chunks()方法分割成多个片段来上传
            for chunk in file.chunks():
                fp.write(chunk)
        file_path = f'survey_system/{dir_name}/{new_file_name}'

        # 写入后创建一条记录
        # FileHistory.objects.create(upload_key=upload_key, path=file_path)

        res_data = {
            'url': file_path,
            'content_type': file.content_type,
            "full_url": f"{settings.FILE_URL}{file_path}",
            'name': new_file_name,
        }

        return Response(res_data)


# 调查
class SurveyViewSet(mixins.RetrieveModelMixin,
                    mixins.ListModelMixin,
                    GenericViewSet):
    queryset = Survey.objects.select_related('module').filter(is_active=True)
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    serializer_class = SurveySerializer
    pagination_class = Pagination
    permission_classes = [IsAuthenticated]  # 验证过的用户才有权限
    ordering_fields = ('id',)
    filter_class = SurveyFilter

    def list(self, request, *args, **kwargs):
        user = request.user
        queryset = self.get_queryset()
        if not user.is_admin():
            queryset = queryset.filter(account=user)
        queryset = self.filter_queryset(queryset).order_by('-updated_time')

        survey_account_qs = SurveyAccount.objects.filter(survey__in=queryset, status__in=[1, 2])\
            .values_list('survey_id', flat=True)
        survey_account_count = Counter(survey_account_qs)
        survey_question_qs = SurveyQuestion.objects.filter(survey_qs_cate__survey__in=queryset)\
            .values_list('survey_qs_cate__survey_id', flat=True)
        survey_question_count = Counter(survey_question_qs)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True, context={'survey_account_count': survey_account_count,
                                                                       'survey_question_count': survey_question_count})
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True, context={'survey_account_count': survey_account_count,
                                                                       'survey_question_count': survey_question_count})
        return Response(serializer.data)

    @action(methods=['get'], detail=True, url_path='write_situation')
    def get_write_situation(self, request, pk=None):
        """ 获取问卷的填写情况， 已完成、未完成、未填写各占多少比例 """

        qs = SurveyAccount.objects.filter(survey_id=pk).values_list('status', flat=True)  # 获取该问卷填写对象的填写状态
        counter = Counter(qs)  # 计算每一种状态的总数
        no_write_cnt = counter[0]  # 通过对象的形式获取各个状态的数量
        no_finish_cnt = counter[1]
        finished_cnt = counter[2]
        all_cnt = len(qs)
        no_write_rate = "%.2f%%" % ((no_write_cnt / all_cnt) * 100)  # 计算每种状态的百分比
        no_finish_rate = "%.2f%%" % ((no_finish_cnt / all_cnt) * 100)
        finished_rate = "%.2f%%" % ((finished_cnt / all_cnt) * 100)
        write_situation = [
                              {
                                'icon': 'evaluate_fill',
                                'color': 'red',
                                'name': '已完成',
                                'rate': finished_rate
                              }, {
                                'icon': 'attentionfavorfill',
                                'color': 'orange',
                                'name': '未完成',
                                'rate': no_finish_rate
                              }, {
                                'icon': 'warnfill',
                                'color': 'yellow',
                                'name': '未填写',
                                'rate': no_write_rate
                              }
                          ],
        return Response(write_situation)

    @action(methods=['get'], detail=True, url_path='survey_score_rank')
    def get_survey_score_rank(self, request, pk=None):
        """ 获取问卷的分数排行榜（从高排到低） """
        name = request.query_params.get('name', None)
        qs = SurveyAccount.objects.filter(survey_id=pk)
        if name:  # 可根据名字或学号过滤
            qs = qs.filter(Q(username=name) | Q(realname__icontains=name))

        qs = qs.values('id', 'username', 'realname', 'status', 'faculty_title')

        survey_account_ids = []
        for i in qs:  # 获取除了未填写状态的填写对象id
            if i['status'] != 0:
                survey_account_ids.append(i['id'])

        survey_answer_qs = SurveyAnswer.objects.filter(survey_account_id__in=survey_account_ids)\
            .values('survey_account_id', 'score').order_by('survey_account_id')  # 获取填写的的分数

        for i in qs:  # 计算每个人的分数
            score = 0
            if i['status'] != 0:
                for j in survey_answer_qs:
                    if i['id'] == j['survey_account_id']:
                        score = score + j['score']
            i['score'] = score

        data = sorted(list(qs), key=lambda d: d['score'], reverse=True)  # 按照分数降序

        # 分页
        page = request.query_params.get('page', None)
        limit = request.query_params.get('limit', None)
        try:
            page = int(page)
            limit = int(limit)
        except:
            page, limit = None, None
        if page and limit:
            total = len(data)  # 数据总量
            data = data[(page - 1) * limit: page * limit]
            return Response({'results': data, 'count': total})
        else:
            return Response(data)

    @action(methods=['get'], detail=True, url_path='write_rate')
    def get_write_rate(self, request, pk=None):
        """ 获取问卷的填写率表格数据 """

        qs = SurveyAccount.objects.filter(survey_id=pk).values_list('status', flat=True)
        counter = Counter(qs)
        no_write_cnt = counter[0]
        no_finish_cnt = counter[1]
        finished_cnt = counter[2]
        all_cnt = len(qs)
        no_write_rate = "%.2f%%" % ((no_write_cnt / all_cnt) * 100)
        no_finish_rate = "%.2f%%" % ((no_finish_cnt / all_cnt) * 100)
        finished_rate = "%.2f%%" % ((finished_cnt / all_cnt) * 100)

        res_list = [
            {'id': None, 'data': ['类型', '人数', '总人数', '所占比例']},
            {'id': 1, 'data': ['已完成', finished_cnt, all_cnt, finished_rate]},
            {'id': 2, 'data': ['未完成', no_finish_cnt, all_cnt, no_finish_rate]},
            {'id': 3, 'data': ['未填写', no_write_cnt, all_cnt, no_write_rate]},

        ]

        return Response({'data': res_list, 'colWidths': ['200', '200', '200', '150']})  # 在小程序展示的表格的每一列的宽度

    @action(methods=['get'], detail=True, url_path='survey_account_score')
    def get_survey_account_score(self, request, pk=None):
        """ 获取填问卷的对象分数状态 """
        name = request.query_params.get('name', None)
        write_status = request.query_params.get('status', None)  # 根据填写状态过滤
        if not write_status:
            return Response({'message': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)

        qs = SurveyAccount.objects.filter(survey_id=pk, status=write_status)
        if name:
            qs = qs.filter(Q(username=name) | Q(realname__icontains=name))

        qs = qs.values('id', 'username', 'realname', 'status', 'faculty_title', 'major_title', 'class_title', 'sex',
                       'grade_name', 'survey', survey_name=F('survey__name'), desc=F('survey__desc'))

        survey_account_ids = [i['id'] for i in qs]

        survey_answer_qs = SurveyAnswer.objects.filter(survey_account_id__in=survey_account_ids) \
            .values('survey_account_id', 'score').order_by('survey_account_id')

        for i in qs:
            score = 0
            for j in survey_answer_qs:
                if i['id'] == j['survey_account_id']:
                    score = score + j['score']
            i['all_score'] = score

        data = sorted(list(qs), key=lambda d: d['all_score'], reverse=True)  # 按照分数降序

        # 分页
        page = request.query_params.get('page', None)
        limit = request.query_params.get('limit', None)
        try:
            page = int(page)
            limit = int(limit)
        except:
            page, limit = None, None
        if page and limit:
            total = len(data)  # 数据总量
            data = data[(page - 1) * limit: page * limit]
            return Response({'results': data, 'count': total})
        else:
            return Response(data)

    @action(methods=['get'], detail=True, url_path='survey_answer_text')
    def get_survey_answer_text(self, request, pk=None):
        """ 获取问卷的简单题（老师进行批改） """
        is_corrected = request.query_params.get('is_corrected', 0)

        cate_objs = SurveyQuestionCategory.objects.filter(survey_id=pk).values()
        cate_ids = [i['id'] for i in cate_objs]
        question_qs = SurveyQuestion.objects.select_related('survey_qs_cate')\
            .filter(survey_qs_cate_id__in=cate_ids, score__gt=0, type__in=[3, 4])\
            .values('id', 'name', 'score', 'file', cate_name=F('survey_qs_cate__category_name'))

        question_dict = {}
        question_id_ls = []
        for i in question_qs:
            i['image'] = []
            i['audio'] = []
            i['video'] = []
            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}"
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['video'].append(full_file_path)
            question_id_ls.append(i['id'])
            question_dict[i['id']] = i

        survey_answer_qs = SurveyAnswer.objects.select_related('question')\
            .filter(question_id__in=question_id_ls, is_corrected=is_corrected)\
            .values('score', 'question_id', 'score', 'file', 'answer_text', 'id')

        for i in survey_answer_qs:
            i['answer_image'] = []
            i['answer_audio'] = []
            i['answer_video'] = []
            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}"
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['answer_image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['answer_audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['answer_video'].append(full_file_path)

            i['question_dict'] = question_dict[i['question_id']]

        return Response(survey_answer_qs)

    @action(methods=['post'], detail=False, url_path='correct_answer_text')
    def correct_answer_text(self, request, pk=None):
        """ 批改简答题 """
        survey_answer_id = request.data.get('id', None)
        score = request.data.get('score', 0)
        try:
            survey_qs = SurveyAnswer.objects.only('id').get(id=survey_answer_id)
        except SurveyAnswer.DoesNotExist:
            return Response({'message': '不存在该问卷答案！'}, status=status.HTTP_400_BAD_REQUEST)

        survey_qs.score = score
        survey_qs.is_corrected = 1
        survey_qs.save()

        return Response({'message': '批改成功！'}, status=status.HTTP_200_OK)


# 调查问卷填写的人
class SurveyAccountViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    queryset = SurveyAccount.objects.select_related('survey').filter(survey__is_active=True)
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    serializer_class = SurveyAccountSerializer
    pagination_class = Pagination
    permission_classes = [IsAuthenticated]  # 验证过的用户才有权限
    ordering_fields = ('id',)
    filter_class = SurveyAccountFilter

    def list(self, request, *args, **kwargs):
        user = request.user
        queryset = self.get_queryset().filter(username=user.username)
        queryset = self.filter_queryset(queryset)

        survey_id_lst = []
        for qs in queryset:
            if qs.status == 0:
                survey_id_lst.append(qs.survey_id)

        survey_account_qs = SurveyAccount.objects.filter(survey_id__in=survey_id_lst, status__in=[1, 2]) \
            .values_list('survey_id', flat=True)
        survey_account_count = Counter(survey_account_qs)
        survey_question_qs = SurveyQuestion.objects.filter(survey_qs_cate__survey_id__in=survey_id_lst) \
            .values_list('survey_qs_cate__survey_id', flat=True)
        survey_question_count = Counter(survey_question_qs)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True, context={'survey_account_count': survey_account_count,
                                                                       'survey_question_count': survey_question_count})
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(page, many=True, context={'survey_account_count': survey_account_count,
                                                                   'survey_question_count': survey_question_count})
        return Response(serializer.data)

    @action(methods=['get'], detail=False, url_path='finished_survey')
    def get_finished_survey(self, request, pk=None):
        """ 学生获取已完成的问卷调查 """
        user = request.user
        now_datetime = datetime.datetime.now()  # 获取已填完的问卷或已结束的问卷
        queryset = self.get_queryset().filter(Q(status=2) | Q(survey__end_time__lt=now_datetime),
                                              survey__is_active=True, username=user.username).order_by("-updated_time")
        queryset = self.filter_queryset(queryset)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = FinishedSurveyAccountSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = FinishedSurveyAccountSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(methods=['get'], detail=False, url_path='not_finished_survey')
    def get_not_finished_survey(self, request, pk=None):
        """ 学生获取未完成或未填写的问卷调查 """
        user = request.user
        now_datetime = datetime.datetime.now()  # 获取未填写或未填完的问卷并未结束的问卷
        queryset = self.get_queryset().filter(username=user.username, status__in=[1, 0], survey__is_active=True,
                                              survey__end_time__gte=now_datetime).order_by("-updated_time")
        queryset = self.filter_queryset(queryset)

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

    @action(methods=['get'], detail=False, url_path='survey_question')
    def get_survey_question(self, request, pk=None):
        """
            学生获取调查问卷问题（未填写状态的）
            格式：
            [{'分类', children:[{'问题', children:[{'选项'}]}]}]

        """
        survey_id = request.query_params.get('survey_id', None)
        if not survey_id:
            return Response({'message': '需要调查问卷'}, status=status.HTTP_400_BAD_REQUEST)
        cate_objs = SurveyQuestionCategory.objects.filter(survey_id=survey_id).values()
        cate_ids = [i['id'] for i in cate_objs]
        question_qs = SurveyQuestion.objects.filter(survey_qs_cate_id__in=cate_ids).values()

        cate_children = {i['id']: [] for i in cate_objs}
        question_ids = [i['id'] for i in question_qs]
        question_option_qs = SurveyQuestionOption.objects.filter(question_id__in=question_ids).values()

        question_children = {i['id']: [] for i in question_qs}

        for i in question_option_qs:  # 给每个选项的文件序列化
            i['image'] = []
            i['audio'] = []
            i['video'] = []
            i['disabled'] = False
            i['selected'] = False
            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}" if 'http' not in file_path else file_path
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['video'].append(full_file_path)
            question_children[i['question_id']].append(i)  # 方便获取每个问题的选项

        for i in question_qs:  # 给每个选项的文件序列化
            i['image'] = []
            i['audio'] = []
            i['video'] = []
            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}"
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['video'].append(full_file_path)
            i['children'] = question_children[i['id']]
            cate_children[i['survey_qs_cate_id']].append(i)  # 方便获取每个分类的问题

        res_data = []
        for i in cate_objs:
            i['children'] = cate_children[i['id']]
            res_data.append(i)

        data = {
            'message': "获取成功！",
            'data': res_data,
            'now_time': datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")
        }

        return Response(data)

    @action(methods=['get'], detail=False, url_path='survey_question_answer')
    def get_survey_question_answer(self, request, pk=None):
        """ 学生获取调查问卷问题（填过状态的） """
        survey_id = request.query_params.get('survey_id', None)
        survey_account = request.query_params.get('survey_account', None)
        if not all([survey_id, survey_account]):
            return Response({'message': '需要调查问卷'}, status=status.HTTP_400_BAD_REQUEST)
        cate_objs = SurveyQuestionCategory.objects.filter(survey_id=survey_id).values()
        cate_ids = [i['id'] for i in cate_objs]
        question_qs = SurveyQuestion.objects.filter(survey_qs_cate_id__in=cate_ids).values()

        cate_children = {i['id']: [] for i in cate_objs}
        question_ids = [i['id'] for i in question_qs]
        question_option_qs = SurveyQuestionOption.objects.filter(question_id__in=question_ids).values()
        question_children = {i['id']: [] for i in question_qs}

        question_answer_qs = SurveyAnswer.objects.filter(survey_account_id=survey_account)\
            .values('question_id', 'answer_id_lst', 'answer_text', 'file')

        question_answer_dict = {answer['question_id']: answer for answer in question_answer_qs}

        for i in question_option_qs:
            i['image'] = []
            i['audio'] = []
            i['video'] = []
            i['disabled'] = False
            answer_options_ls = question_answer_dict[i['question_id']]['answer_id_lst']
            if str(i['id']) in answer_options_ls:
                i['selected'] = True
            else:
                i['selected'] = False
            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}" if 'http' not in file_path else file_path
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['video'].append(full_file_path)
            question_children[i['question_id']].append(i)

        for i in question_qs:
            i['image'] = []
            i['audio'] = []
            i['video'] = []
            if i['type'] == 3:
                i['answer_text'] = question_answer_dict[i['id']]['answer_text']
            elif i['type'] == 2 and i['is_need_limit']:
                if i['limit_choice_count'] == len(question_answer_dict[i['id']]['answer_id_lst']):
                    for j in question_children[i['id']]:
                        if j['selected'] == False:
                            j['disabled'] = True
            elif i['type'] == 4:
                if i['answer_need_text']:
                   i['answer_text'] = question_answer_dict[i['id']]['answer_text']

                if i['answer_need_option'] and i['option_type'] == 2 and i['is_need_limit']:
                    if i['limit_choice_count'] == len(question_answer_dict[i['id']]['answer_id_lst']):
                        for j in question_children[i['id']]:
                            if j['selected'] == False:
                                j['disabled'] = True

                upload_file = question_answer_dict[i['id']]['file']
                answer_file = set()
                for file in upload_file:
                    answer_file.add(file['url'])
                    file['full_url'] = f"{settings.FILE_URL}{file['url']}"
                i['upload_file'] = upload_file
                i['answer_file'] = answer_file
            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}"
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['video'].append(full_file_path)
            i['children'] = question_children[i['id']]
            cate_children[i['survey_qs_cate_id']].append(i)

        res_data = []
        for i in cate_objs:
            i['children'] = cate_children[i['id']]
            res_data.append(i)

        data = {
            'message': "获取成功！",
            'data': res_data,
            'now_time': datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")
        }

        return Response(data)

    @action(methods=['post'], detail=False, url_path='save_question_answer')
    def save_question_answer(self, request, pk=None):
        """ 保存答案 """
        answer_ls = request.data.get('answer_ls', [])
        survey_account = request.data.get('survey_account', '')
        upload_key = request.data.get('upload_key', '')
        submit = request.data.get('submit', 0)
        submit = int(submit)
        start_time = request.data.get('start_time', '')

        if not all([answer_ls, survey_account, upload_key, start_time]):
            return Response({'message': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            survey_qs = SurveyAccount.objects.only('id').get(id=survey_account)
        except SurveyAccount.DoesNotExist:
            return Response({'message': '该用户无权限填写该问卷！'}, status=status.HTTP_400_BAD_REQUEST)

        now_datetime = datetime.datetime.now()
        if now_datetime >= survey_qs.survey.end_time:
            return Response({'message': '该问卷已填写结束！'}, status=status.HTTP_400_BAD_REQUEST)
        elif now_datetime < survey_qs.survey.start_time:
            return Response({'message': '该问卷还未开始！'}, status=status.HTTP_400_BAD_REQUEST)

        if survey_qs.status == 2:
            return Response({'message': '已提交，无法再提交！'}, status=status.HTTP_400_BAD_REQUEST)

        start_time = datetime.datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S')
        time_count = (now_datetime - start_time).total_seconds()  # 包括天数，小时，微秒等在内的所有秒数差
        time_count = round(time_count, 0)
        survey_qs.last_submit_time = now_datetime
        if not survey_qs.use_time:
            survey_qs.use_time = time_count
        else:
            survey_qs.use_time += time_count
        survey_qs.save()

        cate_ids = SurveyQuestionCategory.objects.filter(survey_id=survey_qs.survey_id).values_list('id', flat=True)
        mul_choice_ids = SurveyQuestion.objects.filter(survey_qs_cate_id__in=cate_ids, mul_choice_score_type=2)\
            .values_list('id', flat=True)  # 获取需要全选对答案才得分的问题
        mul_choice_options_qs = SurveyQuestionOption.objects.filter(question_id__in=mul_choice_ids, is_answer=True)\
            .values('id', 'question_id')  # 获取上述问题的正确答案

        mul_choice_dict = {}
        for i in mul_choice_options_qs: # 将每个问题的正确答案分离
            if i['question_id'] not in mul_choice_dict:
                mul_choice_dict[i['question_id']] = []
            mul_choice_dict[i['question_id']].append(i['id'])

        answer_options = []
        for answer in answer_ls:
            if answer['type'] in [1, 2]:
                answer_options = answer_options + answer['answer_id_lst']

        answer_options_qs = SurveyQuestionOption.objects.filter(id__in=answer_options).values('id', 'score')
        options_score_dict = {option['id']: option['score'] for option in answer_options_qs}

        if survey_qs.status != 0:  # 判断是否已填写过
            bulk_update_data = []
            del_file = set()  # 需删除的文件
            new_file = set()  # 新增的文件
            answer_dict = {}
            for answer in answer_ls:
                score = 0

                if answer['type'] == 1:  # 单选题的计分方式
                    for i in answer['answer_id_lst']:
                        score = score + options_score_dict[int(i)]
                elif answer['type'] == 2:  # 多选题的计分方式
                    if answer['mul_choice_score_type'] == 2:  # 如果是全部答案都选了才计分
                       answer_list =[ int(i) for i in answer['answer_id_lst']]
                       if mul_choice_dict[answer['id']] == answer_list:  # 判断是否都选了
                           score = answer['score']
                    else:
                        for i in answer['answer_id_lst']:
                            score = score + options_score_dict[int(i)]
                elif answer['type'] == 4:  # 如果是文件题
                    for file_dict in answer['upload_file']:
                        new_file.add(file_dict['url'])
                        del file_dict['full_url']
                    item_del_file = set(answer['answer_file']) - new_file
                    del_file = del_file | item_del_file
                answer['score'] = score if score >= 0 else 0  # 判断有可能出现负分数的情况
                answer_dict[answer['id']] = answer

            answer_qs = SurveyAnswer.objects.filter(survey_account_id=survey_account)  # 获取最新一次的填写答案
            for answer in answer_qs:  # 循环更新答案
                answer_obj = answer_dict.get(answer.question_id, {})
                if answer_obj:
                    answer.answer_id_lst = answer_obj.get('answer_id_lst', [])
                    answer.answer_text = answer_obj.get('answer_text', '')
                    answer.file = answer_obj.get('upload_file', [])
                    answer.score = answer_obj.get('score', 0)
                    bulk_update_data.append(answer)
            if bulk_update_data:  # 批量更新，只生成一条sql语句
                SurveyAnswer.objects.bulk_update(bulk_update_data, ['answer_id_lst', 'answer_text', 'file', 'score'])
            if submit == 1:  # 如果是提交，则将填写的状态改为已完成
                SurveyAccount.objects.filter(id=survey_account).update(status=2)
            # FileHistory.objects.filter(path__in=list(new_file)).update(need_delete=0)  # 更新新文件的状态
            # FileHistory.objects.filter(path__in=list(del_file)).update(need_delete=1)  # 更新需删除的文件的状态

        else:  # 如果是第一次提交
            bulk_create_data = []
            new_file = set()  # 新文件
            for answer in answer_ls:
                score = 0

                if answer['type'] == 1:
                    for i in answer['answer_id_lst']:
                        score = score + options_score_dict[int(i)]
                elif answer['type'] == 2:
                    if answer['mul_choice_score_type'] == 2:
                        answer_list = [int(i) for i in answer['answer_id_lst']]
                        if mul_choice_dict[answer['id']] == answer_list:
                            score = answer['score']
                    else:
                        for i in answer['answer_id_lst']:
                            score = score + options_score_dict[int(i)]
                elif answer['type'] == 4:  # 如果有文件
                    for file_dict in answer['upload_file']:
                        new_file.add(file_dict['url'])
                        del file_dict['full_url']
                answer_obj = SurveyAnswer(survey_account_id=survey_account, question_id=answer['id'],
                                          answer_id_lst=answer.get('answer_id_lst', []),
                                          answer_text=answer.get('answer_text', None),
                                          file=answer.get('upload_file', []),
                                          score=score)
                bulk_create_data.append(answer_obj)

            if bulk_create_data:  # 批量创建
                SurveyAnswer.objects.bulk_create(bulk_create_data, batch_size=500, ignore_conflicts=True)
            if submit == 1:  # 如果是提交，则将填写的状态改为已完成
                SurveyAccount.objects.filter(id=survey_account).update(status=2)
            else:  # 如果是保存，则将填写的状态改为未完成
                SurveyAccount.objects.filter(id=survey_account).update(status=1)
            # FileHistory.objects.filter(path__in=list(new_file)).update(need_delete=0)  # 更新新文件的状态
        if submit == 1:
            return Response({'message': '提交成功！'}, status=status.HTTP_200_OK)
        return Response({'message': '保存成功！'}, status=status.HTTP_200_OK)

    @action(methods=['get'], detail=False, url_path='question_answer_analysis')
    def get_question_answer_analysis(self, request, pk=None):
        """ 学生获取调查问卷问题答案分析（填完的状态的） """
        survey_id = request.query_params.get('survey_id', None)
        survey_account = request.query_params.get('survey_account', None)
        if not all([survey_id, survey_account]):
            return Response({'message': '需要调查问卷'}, status=status.HTTP_400_BAD_REQUEST)
        cate_objs = SurveyQuestionCategory.objects.filter(survey_id=survey_id).values()
        cate_ids = [i['id'] for i in cate_objs]
        question_qs = SurveyQuestion.objects.filter(survey_qs_cate_id__in=cate_ids).values()

        cate_children = {i['id']: [] for i in cate_objs}
        question_ids = [i['id'] for i in question_qs]
        question_option_qs = SurveyQuestionOption.objects.filter(question_id__in=question_ids).values()
        question_children = {i['id']: [] for i in question_qs}

        question_answer_qs = SurveyAnswer.objects.filter(survey_account_id=survey_account) \
            .values('question_id', 'answer_id_lst', 'answer_text', 'file', 'score')

        question_answer_dict = {answer['question_id']: answer for answer in question_answer_qs}

        for i in question_option_qs:
            i['image'] = []
            i['audio'] = []
            i['video'] = []
            i['disabled'] = False
            answer_options_ls = question_answer_dict[i['question_id']]['answer_id_lst']
            if str(i['id']) in answer_options_ls:
                i['selected'] = True
            else:
                i['selected'] = False
            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}"
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['video'].append(full_file_path)
            question_children[i['question_id']].append(i)

        for i in question_qs:
            i['image'] = []
            i['audio'] = []
            i['video'] = []
            i['got_score'] = question_answer_dict[i['id']]['score']
            if i['type'] == 3:
                i['answer_text'] = question_answer_dict[i['id']]['answer_text']
            elif i['type'] == 2 and i['is_need_limit']:
                if i['limit_choice_count'] == len(question_answer_dict[i['id']]['answer_id_lst']):
                    for j in question_children[i['id']]:
                        if j['selected'] == False:
                            j['disabled'] = True
            elif i['type'] == 4:
                if i['answer_need_text']:
                    i['answer_text'] = question_answer_dict[i['id']]['answer_text']

                if i['answer_need_option'] and i['option_type'] == 2 and i['is_need_limit']:
                    if i['limit_choice_count'] == len(question_answer_dict[i['id']]['answer_id_lst']):
                        for j in question_children[i['id']]:
                            if j['selected'] == False:
                                j['disabled'] = True

                i['answer_image'] = []
                i['answer_video'] = []
                i['answer_audio'] = []

                upload_file = question_answer_dict[i['id']]['file']
                answer_file = set()
                for file in upload_file:
                    answer_file.add(file['url'])
                    full_url = f"{settings.FILE_URL}{file['url']}" if 'http' not in file['url'] else file['url']
                    file['full_url'] = full_url

                    file_type = file['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['answer_image'].append(full_url)
                    elif file_type == 'audio':
                        i['answer_audio'].append(full_url)
                    elif file_type == 'video':
                        i['answer_video'].append(full_url)

                i['upload_file'] = upload_file
                i['answer_file'] = answer_file

            if i['file']:
                for j in i['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}"
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    if file_type == 'image':
                        i['image'].append(full_file_path)
                    elif file_type == 'audio':
                        i['audio'].append(full_file_path)
                    elif file_type == 'video':
                        i['video'].append(full_file_path)
            i['children'] = question_children[i['id']]
            cate_children[i['survey_qs_cate_id']].append(i)

        res_data = []
        for i in cate_objs:

            i['children'] = cate_children[i['id']]
            score = 0
            got_score = 0
            for j in i['children']:
                score = score + j['score']
                got_score = got_score + j['got_score']
            i['score'] = score
            i['got_score'] = got_score
            res_data.append(i)

        return Response(res_data)

    @action(methods=['get'], detail=False, url_path='answer_analysis')
    def get_answer_analysis(self, request, pk=None):
        """ 学生获取调查答案分析（填完的状态的） 获取每一个维度的分数"""
        survey_id = request.query_params.get('survey_id', None)
        survey_account = request.query_params.get('survey_account', None)
        if not all([survey_id, survey_account]):
            return Response({'message': '需要调查问卷'}, status=status.HTTP_400_BAD_REQUEST)
        cate_objs = SurveyQuestionCategory.objects.filter(survey_id=survey_id).values()
        cate_ids = []
        cate_children = {}
        cate_questions_id = {}
        question_ids = []
        for i in cate_objs:
            cate_ids.append(i['id'])
            cate_children[i['id']] = []
            cate_questions_id[i['id']] = []

        # cate_ids = [i['id'] for i in cate_objs]
        question_qs = SurveyQuestion.objects.filter(survey_qs_cate_id__in=cate_ids)\
            .values('id', 'score', 'survey_qs_cate_id')
        # cate_children = {i['id']: [] for i in cate_objs}
        question_answer_qs = SurveyAnswer.objects.filter(survey_account_id=survey_account) \
            .values('question_id', 'score', class_title=F('survey_account__class_title'))
        question_answer_ls = list(question_answer_qs)
        question_answer_dict = {answer['question_id']: answer for answer in question_answer_ls}

        for i in question_qs:
            i['got_score'] = question_answer_dict[i['id']]['score']
            cate_children[i['survey_qs_cate_id']].append(i)
            cate_questions_id[i['survey_qs_cate_id']].append(i['id'])
            question_ids.append(i['id'])

        answer_qs = SurveyAnswer.objects.filter(question_id__in=question_ids) \
            .values('question_id', 'score', class_title=F('survey_account__class_title'))

        survey_account_qs = SurveyAccount.objects.filter(survey_id=survey_id, status__in=[1, 2]).values('class_title', 'id')
        class_account = 0
        all_account = len(survey_account_qs)
        if question_answer_ls[0]['class_title']:
            for i in survey_account_qs:
                if i['class_title'] == question_answer_ls[0]['class_title']:
                    class_account += 1


        res_data = [
            # {'id': None, 'data': ['维度名', '维度问题个数', '维度总分', '个人总得分', '个人平均分', '班级填写人数', '班级平均分',  '总填写人数', '总平均分']},
            {'id': None, 'data': ['维度名', '个人总得分', '个人平均分', '班级平均分', '总平均分']},
        ]

        cate_full_score = []  # 每个维度的最大值
        people_data = []  # 个人数据
        class_data = []  # 班级数据
        all_data = []  # 全部数据

        for i in cate_objs:
            item_dict = {
                'id': i['id'],
                'data': []
            }
            class_all_score = 0
            all_score = 0

            account_answer = cate_children[i['id']]
            score = 0
            got_score = 0
            question_count = 0

            for k in answer_qs:
                if k['question_id'] in cate_questions_id[i['id']]:
                    all_score += k['score']
                    if question_answer_ls[0]['class_title'] and question_answer_ls[0]['class_title'] == k['class_title']:
                        class_all_score += k['score']

            for j in account_answer:
                question_count = question_count + 1
                score = score + j['score']
                got_score = got_score + j['got_score']

            person_avg_score = round(got_score / question_count, 1)

            if class_account == 0:
                class_avg_score = 0
                class_accounts = 0
            else:
                class_avg_score = round(class_all_score / (question_count * class_account), 1)
                class_accounts = class_account

            all_avg_score = round(all_score / (question_count * all_account), 1)

            # data = [i['category_name'], question_count, score, got_score, person_avg_score,
            #         class_accounts, class_avg_score, all_account, all_avg_score]
            data = [i['category_name'], got_score, person_avg_score, class_avg_score, all_avg_score]

            item_dict['data'] = data
            res_data.append(item_dict)

            max_value = class_avg_score if class_avg_score >= person_avg_score else person_avg_score
            max_value = max_value if max_value >= all_avg_score else all_avg_score
            cate_full_score.append({'name': i['category_name'], 'max': max_value})
            people_data.append(person_avg_score)
            class_data.append(class_avg_score)
            all_data.append(all_avg_score)

        series_data = [
            {'name': '个人平均分', 'value': people_data},
            {'name': '班级平均分', 'value': class_data},
            {'name': '总平均分', 'value': all_data},
        ]

        legend_data = [x['name'] for x in series_data]

        cates_balance_data = {
            'indicator_data': cate_full_score,
            'legend_data': legend_data,
            'series_data': series_data
        }

        return Response({'data': res_data, 'res_data': cates_balance_data, 'colWidths': ['200', '150', '150', '150', '150']})  # 在小程序展示的表格的每一列的宽度

    @action(methods=['get'], detail=False, url_path='survey_count')
    def get_survey_count(self, request, pk=None):
        survey_qs = SurveyAccount.objects.filter(username=request.user.username, survey__is_active=True).values_list('status', flat=True)
        counter = Counter(survey_qs)
        data = {
            '0': 0,
            '1': 0,
            '2': 0
        }
        for status, cnt in counter.items():
            data[status] = cnt
        return Response(data)


# 轮播图
class SwiperViewSet(mixins.ListModelMixin,
                    GenericViewSet):
    queryset = Swiper.objects.filter(is_active=True).select_related('account')
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    serializer_class = SwiperSerializer
    pagination_class = Pagination
    ordering_fields = ('id', 'created_time')
    filter_fields = ['is_active']


# 模块课程
class ModuleViewSet(mixins.ListModelMixin,
                    mixins.RetrieveModelMixin,
                    GenericViewSet):
    queryset = Module.objects.all()
    filter_backends = (DjangoFilterBackend, OrderingFilter)
    serializer_class = ModuleListSerializer
    pagination_class = Pagination
    ordering_fields = ('id', 'created_time')
    filter_class = ModuleFilter

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return ModuleRetrieveSerializer
        return ModuleListSerializer


# 只用于上传微信头像
class UploadWXPhotoViewSet(GenericViewSet):
    permission_classes = [IsAuthenticated]

    @action(methods=['post'], detail=False, url_path='upload')
    def upload_file(self, request, pk=None):
        """ 上传图片 """
        file = request.data.get('file', None)   # 上传的文件
        dir_name = request.data.get('dir_name', '')     # 需要保存在哪里
        if not all([file, dir_name]):
            return Response({'message': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)
        if file.content_type.split('/')[0] not in ['image']:
            return Response({'message': '上传文件出错：上传了不允许的文件类型。'}, status=status.HTTP_400_BAD_REQUEST)

        file_name = file.name
        dir_path = f"{settings.MEDIA_ROOT}/survey_system/{dir_name}"
        if not os.path.exists(dir_path):  # 没有该目录就创建
            os.makedirs(dir_path)
        # 给文件重新命名，避免重复
        now_str = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        new_file_name = f"{now_str}-{file_name}"
        file_path = os.path.join(dir_path, new_file_name)
        # 写入文件
        with open(file_path, 'ab') as fp:
            # 如果上传的文件非常大，就通过chunks()方法分割成多个片段来上传
            for chunk in file.chunks():
                fp.write(chunk)
        file_path = f'survey_system/{dir_name}/{new_file_name}'

        user = request.user
        user.wx_photo = file_path
        user.save()

        res_data = {
            'url': file_path,
            'content_type': file.content_type,
            "full_url": f"{settings.FILE_URL}{file_path}",
            'name': new_file_name,
        }

        return Response(res_data)